package com.haowan.accessibilityservice;

import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.GestureDescription;
import android.content.Intent;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.media.AudioManager;
import android.os.Build;
import android.os.Build.VERSION;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Button;
import android.widget.FrameLayout;

import androidx.annotation.RequiresApi;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Random;

public class GlobalActionBarService extends AccessibilityService {

    private static final String TAG = "GlobalActionBarService";

    private FrameLayout mLayout;


    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }

    @Override
    protected void onServiceConnected() {
        Log.d(TAG, "onServiceConnected");

        // Create an overlay and display the action bar
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        mLayout = new FrameLayout(this);
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
        lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
        lp.format = PixelFormat.TRANSLUCENT;
        lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
        lp.gravity = Gravity.TOP;
        LayoutInflater inflater = LayoutInflater.from(this);
        inflater.inflate(R.layout.action_bar, mLayout);
        wm.addView(mLayout, lp);

        configurePowerButton();
        configureVolumeButton();
        configureScrollButton();
        configureSwipeButton();
        configClickButton();
        simulateGoHome();
        simulateBack();
        simulateNotification();
    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        Log.d(TAG, "onAccessibilityEvent");
        final int eventType = event.getEventType();
        String eventText = null;
        switch(eventType) {
            case AccessibilityEvent.TYPE_VIEW_CLICKED:
                eventText = "TYPE_VIEW_CLICKED: ";
                break;
            case AccessibilityEvent.TYPE_VIEW_FOCUSED:
                eventText = "TYPE_VIEW_FOCUSED: ";
                break;
            case AccessibilityEvent.TYPE_VIEW_LONG_CLICKED:
                eventText = "TYPE_VIEW_LONG_CLICKED ";
                break;
            case AccessibilityEvent.TYPE_VIEW_SELECTED:
                eventText = "TYPE_VIEW_SELECTED ";
                break;
            case 16:
                eventText = "TYPE_VIEW_TEXT_CHANGED ";
                break;
            case 32:
                eventText = "TYPE_WINDOW_STATE_CHANGED ";
                break;
            case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
                eventText = "TYPE_NOTIFICATION_STATE_CHANGED ";
                break;
            case 128:
                eventText = "TYPE_VIEW_HOVER_ENTER ";
                break;
            case 256:
                eventText = "TYPE_VIEW_HOVER_EXIT ";
                break;
            case 512:
                eventText = "TYPE_TOUCH_EXPLORATION_GESTURE_START ";
                break;
            case 1024:
                eventText = "TYPE_TOUCH_EXPLORATION_GESTURE_END ";
                break;
            case 2048:
                // 这个出现的很频繁
                eventText = "TYPE_WINDOW_CONTENT_CHANGED ";
                break;
            case 4096:
                eventText = "TYPE_VIEW_SCROLLED ";
                break;
            case 8192:
                eventText = "TYPE_VIEW_TEXT_SELECTION_CHANGED ";
                break;
            case 16384:
                eventText = "TYPE_ANNOUNCEMENT ";
                break;
            case 1048576:
                eventText = "TYPE_TOUCH_INTERACTION_START ";
                break;
            case 2097152:
                eventText = "TYPE_TOUCH_INTERACTION_END ";
                break;
            default:
                eventText = "Default -> " + eventType;
                break;
        }

        eventText = eventText + event.getContentDescription();
        Log.d(TAG, "eventText -> " + eventText);
    }

    @Override
    public void onInterrupt() {
        Log.d(TAG, "onInterrupt");
    }

    private void configurePowerButton() {
        Button powerButton = (Button) mLayout.findViewById(R.id.power);
        powerButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                performGlobalAction(GLOBAL_ACTION_POWER_DIALOG);
            }
        });
    }

    private void configureVolumeButton() {
        Button volumeUpButton = (Button) mLayout.findViewById(R.id.volume_up);
        volumeUpButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
                audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,
                        AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
            }
        });
    }


    private AccessibilityNodeInfo findScrollableNode(AccessibilityNodeInfo root) {
        Deque<AccessibilityNodeInfo> deque = new ArrayDeque<>();
        deque.add(root);
        while (!deque.isEmpty()) {
            AccessibilityNodeInfo node = deque.removeFirst();
            if (node.getActionList().contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD)) {
                return node;
            }
            for (int i = 0; i < node.getChildCount(); i++) {
                deque.addLast(node.getChild(i));
            }
        }
        return null;
    }

    private void configureScrollButton() {
        Button scrollButton = (Button) mLayout.findViewById(R.id.scroll);
        scrollButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                AccessibilityNodeInfo scrollable = findScrollableNode(getRootInActiveWindow());
                if (scrollable != null) {
                    scrollable.performAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId());
                }
            }
        });
    }

    private void configureSwipeButton() {
        Button swipeButton = (Button) mLayout.findViewById(R.id.swipe);
        swipeButton.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.N)
            @Override
            public void onClick(View view) {
                Path swipePath = new Path();
                swipePath.moveTo(700, 100);
                swipePath.lineTo(700, 300);
                GestureDescription.Builder gestureBuilder = new GestureDescription.Builder();
                gestureBuilder.addStroke(new GestureDescription.StrokeDescription(swipePath, 0, 500));
                dispatchGesture(gestureBuilder.build(), null, null);
            }
        });
    }

    private void configClickButton() {
        Button clickButton = (Button) mLayout.findViewById(R.id.click);
        clickButton.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.N)
            @Override
            public void onClick(View view) {
                simulateClick(new Point(300,700), 0, 100);
            }
        });
    }

    private void click(AccessibilityEvent event) {
        List<AccessibilityNodeInfo> list  = event.getSource().findAccessibilityNodeInfosByText("确定");
        if (null != list) {
            for (AccessibilityNodeInfo info : list) {
                if (info.getText().toString().equals("确定")) {
                    //找到你的节点以后 就直接点击他就行了
                    info.performAction(AccessibilityNodeInfo.ACTION_FOCUS);
                    info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                }
            }
        }
    }
    //模拟点击
    private boolean simulateClick(Point point, long startTime, long duration) {
        Log.d(TAG, "simulateClick");
        if (VERSION.SDK_INT >= 24) {
            try {
                long j3;
                GestureDescription.Builder builder = new GestureDescription.Builder();
                Path path = new Path();
                path.moveTo((float) point.x, (float) point.y);
                if (duration <= 0) {
                    j3 = 5;
                } else {
                    j3 = duration;
                }
                builder.addStroke(new GestureDescription.StrokeDescription(path, startTime, j3));
                return dispatchGesture(builder.build(), null, null);
            } catch (Throwable e) {
                Log.w(TAG, e);
                return false;
            }
        }
        Log.e(TAG, VERSION.SDK_INT + "should >= Build.VERSION_CODES.N");
        return false;
    }
    // 模拟收缩
    private boolean simulateShrink(Point point, Point point2) {
        Log.d(TAG, "simulateShrink");
        if (VERSION.SDK_INT >= 24) {
            try {
                GestureDescription.Builder builder = new GestureDescription.Builder();
                Path path = new Path();
                path.moveTo((float) ((5 - new Random().nextInt(5)) + point.x), (float) ((5 - new Random().nextInt(5)) + point.y));
                path.lineTo((float) (point.x + 150), (float) (point.y - 150));
                Path path2 = new Path();
                path2.moveTo((float) ((5 - new Random().nextInt(5)) + point2.x), (float) ((5 - new Random().nextInt(5)) + point2.y));
                path2.lineTo((float) (point2.x - 150), (float) (150 + point2.y));
                builder.addStroke(new GestureDescription.StrokeDescription(path, 10, 500));
                builder.addStroke(new GestureDescription.StrokeDescription(path2, 10, 500));
                return dispatchGesture(builder.build(), null, null);
            } catch (Throwable e) {
                Log.w(TAG, e);
                return false;
            }
        }
        Log.e(TAG, VERSION.SDK_INT + "should >= Build.VERSION_CODES.N");
        return false;
    }
    //模拟滑动
    private boolean simulateSwipe(Point point, Point point2, long startTime, long duration) {
        Log.d(TAG, "simulateSwipe position " + point.x + "," + point.y + " end " + point2.x + "," + point2.y + " duration " + duration);
        if (VERSION.SDK_INT >= 24) {
            try {
                long newDuration;
                GestureDescription.Builder builder = new GestureDescription.Builder();
                Path path = new Path();
                path.moveTo((float) point.x, (float) point.y);
                path.lineTo((float) point2.x, (float) point2.y);
                if (duration <= 0) {
                    newDuration = 300; // 模拟滑动时滑动运行时间，一般在300～500ms效果会好一些，太快会导致滑动高度不可控制
                } else {
                    newDuration = duration;
                }
                builder.addStroke(new GestureDescription.StrokeDescription(path, startTime, newDuration));
                return dispatchGesture(builder.build(), null, null);
            } catch (Throwable e) {
                Log.w(TAG, e);
                return false;
            }
        }
        Log.e(TAG, VERSION.SDK_INT + "should >= Build.VERSION_CODES.N");
        return false;
    }

    private void simulateGoHome() {
        Log.d(TAG, "simulateGoHome");
        Button homeButton = (Button) mLayout.findViewById(R.id.home);
        homeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                performGlobalAction(GLOBAL_ACTION_HOME);
            }
        });
    }

    private void simulateBack() {
        Log.d(TAG, "simulateBack");
        Button backButton = (Button) mLayout.findViewById(R.id.back);
        backButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                performGlobalAction(GLOBAL_ACTION_BACK);
            }
        });
    }

    private void simulateNotification() {
        Log.d(TAG, "simulateNotification");
        Button notificationButton = (Button) mLayout.findViewById(R.id.notification);
        notificationButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                performGlobalAction(GLOBAL_ACTION_NOTIFICATIONS);
            }
        });
    }

}
